home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
i_set.exe
/
I-SET.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-04
|
20KB
|
761 lines
/* I-SET.c ****************************************************************
A very simple module to allow modification of master
environment under DOS.
External entry points:
int iset_load_envstrings (BYTEPTR envblock, char *envstrings[], unsigned *pused)
Loads the enviromnment in an array of char *. Each entry
is malloc'd by the function, so it is expected that
iset_free_envstrings is called after use.
This routine was originally internal (used by others in this module)
but it is now public should anyone care. No checking on array
dimensions!
If pfree is not NULL, the functions fills it with the number of
bytes currently used in the environment
int iset_free_envstrings (char *envstrings[])
Frees the copy alloc'd by iset_load_envstrings. It is expected
that the last valid entry in the array is a zero-length string
(iset_load_envstrings does this).
char *iset_getenv (char *env_par)
Just like getenv(), only this works on the original environment.
After use of other functions in this module, the copy which
is accessed by getenv() could be out of date in respect of
the master. Used internally also.
int iset_set_string (char *env_par, char *env_value)
Actually a setenv() on the master environment. If a string
with env_par isn't found, it is added to the environment.
If env_value is NULL, the string is addedd just like UNIX.
Note that this routine does attempt to get the strlen()
of a NULL: in MSC 6.0, the result is 0 and no problem.
Please look out in other cases.
int iset_append_to_string (char *env_par, char *env_value, int before)
Adds a new env_value to the end or the beginning
of the actual value of an environment string, depending
on before (0: append; 1: insert before).
If the string didn't exist, it falls
back to iset_set_string. Otherwise, the string is appended
with a preceding semi-colon.
int iset_cut_string (char *env_par, char *string_to_cut)
The opposite of iset_append_string. If a string with name
env_par is found, string_to_cut is searched between pairs
of semicolons and, if found, the original string is collapsed
to exclude it. If the string isn't found nothing is done.
int iset_delete_string (char *env_par)
Remove the identified string from the environment. This works
also on no-value strings which can be produced by
iset_set_string.
int iset_show_strings (void)
Will output on stdout the contents of the master environment
and (little) additional statistics. Useful for seeing variables
longer than 127 chars, which DOS's set will truncate to 127.
This module has been extensively used. Still we don't expect it to
work in every situation! Do complete testings because alteration
of master environment can produce tricky situations to debug.
You can use this source as you like provided you leave this notes
in the module together with the variable id.
Please note that, to assure reentrancy, all functions load a complete
array of pointers (dimension is hardwired) so stack space might
be an issue.
I-SET was written by Shari (Davide Migliavacca) of Inferentia S.r.l.,
via Venezian 10, 20123 Milano ITALY.
Tel. +39.2.266680568.
CompuServe 100016,2335
**********************************************************/
/* You can't remove this lines */
#define VERSIONE "3.53"
static const char *id= "I-Set " VERSIONE " " __DATE__ " " __TIME__ " Created by Shari CIS 100016,2335";
/*******************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <options.h>
/* Should DOS grow beyond this limit, you may put
a version checking function instead of this macro */
#define dos_max_pathvar_length() 127
int iset_check_length(char *env_par, int len);
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef BYTE _far * BYTEPTR;
typedef WORD _far * WORDPTR;
typedef DWORD _far *DWORDPTR;
typedef void _far *FP;
#define MK_FP(seg, off) ((FP)((DWORD)(((WORD)(off)) | ((DWORD)((WORD)(seg))) << 16 )))
#define INT20h 0xCD20
static char terminating_null = '\0';
union REGS regs;
typedef struct tagPSP {
WORD int20; /* must be 0xCD20 */
WORD alloc_end_seg; /* segment, end of allocation block */
BYTE reserved_1;
BYTE far_call; /* call far ... next field */
DWORD DOS_dispatcher; /* address of DOS dispatcher */
DWORD termination_handler;/* int 22h contents */
DWORD ctrl_c_handler; /* int 23h contents */
DWORD crit_err_handler; /* int 24h contents */
WORD parent_PSP; /* UNDOCUMENTED */
BYTE JFT[20]; /* Job file table: UNDOCUMENTED */
WORD env_seg; /* segment of environment block */
DWORD reserved_2;
WORD max_opens; /* # of entries in JFT: UNDOCUMENTED */
DWORD actual_JFT; /* Address of actual JFT: UNDOCUMENTED */
BYTE reserved_3[36];
BYTE FCB_1[16]; /* Default FCB #1 */
BYTE FCB_2[20]; /* Default FCB #2 (overlaid by 1 if used)*/
BYTE command_tail[128]; /* command tail and DTA */
} PSP;
typedef struct tagMCB {
BYTE type;
WORD owner; /* PSP of owner */
WORD size;
BYTE reserved[3];
BYTE dos4[8];
} MCB;
static unsigned env_size(WORD envseg)
{
unsigned envsize;
_asm {
mov ax,envseg /* get segment of env */
dec ax /* back up to MCB */
mov es,ax
mov ax,es:[0003h] /* get size in grafs */
mov envsize, ax
}
return envsize << 4; /* multiply by paragraph size */
}
/* determines if seg is really a psp:
1) at seg-1 there must be a DOS MCB whose owner is seg
2) the first two bytes in seg must be 0xCD 0x20 (int 20h)
From "Undocumented DOS" by Andrew Schulman, Byte Vol. 16, #3 (March 1991)
*/
static int is_psp (WORD seg)
{
return ((((MCB _far *) MK_FP(seg-1, 0))->owner == seg) &&
(*((WORD _far *) MK_FP(seg, 0)) == INT20h));
}
static WORD get_shell_psp_seg()
{
PSP _far *my_psp;
PSP _far *parent_psp;
/* get PSP address (int 21h fun 62h, DOS >= 3.0) */
regs.h.ah = 0x62;
intdos (®s, ®s);
/* bx contains segment of PSP */
my_psp = (PSP _far *)MK_FP(regs.x.bx, 0);
do {
parent_psp = (PSP _far *)MK_FP(my_psp->parent_PSP, 0);
my_psp = parent_psp;
} while (parent_psp->parent_PSP != FP_SEG(parent_psp));
return FP_SEG(parent_psp);
}
static BYTEPTR get_envblock ()
{
WORD shell_psp_seg;
PSP _far *shell_psp;
shell_psp_seg = get_shell_psp_seg();
shell_psp = (PSP _far *) MK_FP(shell_psp_seg, 0);
return ((BYTEPTR) MK_FP(shell_psp->env_seg, 0));
}
int iset_load_envstrings (BYTEPTR envblock, char *envstrings[], unsigned *pused)
{
char _far *envpointer = (char _far *)envblock;
size_t len;
int i = 0;
while (*envpointer != '\0') {
len = _fstrlen (envpointer);
envstrings[i] = (char *) malloc (len + 1);
_fstrcpy ((char _far *) envstrings[i], envpointer);
envpointer += (len + 1);
++i;
}
envstrings[i] = &terminating_null;
if (pused != (unsigned *)NULL)
*pused = (unsigned) (envpointer - envblock);
return i;
}
int iset_free_envstrings (char *envstrings[])
{
int i = 0;
while (envstrings[i][0] != '\0')
free (envstrings[i++]);
return 0;
}
static int search_string (char *string, char *array[])
{
int i = 0;
while (array[i][0] != '\0')
{
if (!strnicmp(array[i], string, strlen(string)))
return i;
else
i++;
}
return -1;
}
/* works on original environment, which may be different
from our copy because of other iset_... function calls */
char *iset_getenv (char *env_par)
{
char *env_strings[128];
BYTEPTR envblock;
int maxstring;
int i;
static char env_name[128];
static char env_value[256];
char *return_this = NULL;
char *equal;
envblock = get_envblock();
maxstring = iset_load_envstrings (envblock, env_strings, NULL);
env_value[0] = '\0';
for (i = 0; i < maxstring; i++) {
equal = strchr(env_strings[i], '=');
if (equal != NULL) {
strncpy (env_name, env_strings[i], equal - env_strings[i]);
env_name[equal - env_strings[i]]='\0';
}
else
strcpy (env_name, env_strings[i]);